/* uuid.c */

#include <postgres.h>
#include <fmgr.h>

#include <uuid/uuid.h>

PG_MODULE_MAGIC;

Datum polarrose_uuid(PG_FUNCTION_ARGS);

Datum           polarrose_uuid_in(PG_FUNCTION_ARGS);
Datum           polarrose_uuid_out(PG_FUNCTION_ARGS);
//Datum           polarrose_uuid_recv(PG_FUNCTION_ARGS);
//Datum           polarrose_uuid_send(PG_FUNCTION_ARGS);
Datum           polarrose_uuid_abs_lt(PG_FUNCTION_ARGS);
Datum           polarrose_uuid_abs_le(PG_FUNCTION_ARGS);
Datum           polarrose_uuid_abs_eq(PG_FUNCTION_ARGS);
Datum           polarrose_uuid_abs_ge(PG_FUNCTION_ARGS);
Datum           polarrose_uuid_abs_gt(PG_FUNCTION_ARGS);
Datum           polarrose_uuid_abs_cmp(PG_FUNCTION_ARGS);

Datum           polarrose_uuid_to_text(PG_FUNCTION_ARGS);
Datum           polarrose_uuid_from_text(PG_FUNCTION_ARGS);

typedef struct polarrose_uuid_t {
      uuid_t uuid;
} polarrose_uuid_t;

static int polarrose_uuid_cmp_internal(polarrose_uuid_t* a, polarrose_uuid_t* b)
{
   return uuid_compare(a->uuid, b->uuid);
}

PG_FUNCTION_INFO_V1(polarrose_uuid);

Datum polarrose_uuid(PG_FUNCTION_ARGS)
{
   polarrose_uuid_t* result = (polarrose_uuid_t*) palloc(sizeof(polarrose_uuid_t));
   uuid_generate_random(result->uuid);
   
   PG_RETURN_POINTER(result);
}

PG_FUNCTION_INFO_V1(polarrose_uuid_in);

Datum polarrose_uuid_in(PG_FUNCTION_ARGS)
{
   char* ascii = PG_GETARG_CSTRING(0);
   uuid_t uuid;
   polarrose_uuid_t* result;

   if (uuid_parse(ascii, uuid) != 0) {
      ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
        errmsg("invalid input syntax for uuid: \"%s\"", ascii)));
   }

   result = (polarrose_uuid_t*) palloc(sizeof(polarrose_uuid_t));
   memcpy(result->uuid, uuid, sizeof(uuid_t));

   PG_RETURN_POINTER(result);
}

PG_FUNCTION_INFO_V1(polarrose_uuid_out);

Datum polarrose_uuid_out(PG_FUNCTION_ARGS)
{
   polarrose_uuid_t* uuid = (polarrose_uuid_t*) PG_GETARG_POINTER(0);
   char* ascii = (char*) palloc(37);
   uuid_unparse_lower(uuid->uuid, ascii);
   PG_RETURN_CSTRING(ascii);
}

PG_FUNCTION_INFO_V1(polarrose_uuid_abs_lt);

Datum polarrose_uuid_abs_lt(PG_FUNCTION_ARGS)
{
   polarrose_uuid_t* a = (polarrose_uuid_t*) PG_GETARG_POINTER(0);
   polarrose_uuid_t* b = (polarrose_uuid_t*) PG_GETARG_POINTER(1);
   PG_RETURN_BOOL(polarrose_uuid_cmp_internal(a, b) < 0);
}

PG_FUNCTION_INFO_V1(polarrose_uuid_abs_le);

Datum polarrose_uuid_abs_le(PG_FUNCTION_ARGS)
{
   polarrose_uuid_t* a = (polarrose_uuid_t*) PG_GETARG_POINTER(0);
   polarrose_uuid_t* b = (polarrose_uuid_t*) PG_GETARG_POINTER(1);
   PG_RETURN_BOOL(polarrose_uuid_cmp_internal(a, b) <= 0);
}

PG_FUNCTION_INFO_V1(polarrose_uuid_abs_eq);

Datum polarrose_uuid_abs_eq(PG_FUNCTION_ARGS)
{
   polarrose_uuid_t* a = (polarrose_uuid_t*) PG_GETARG_POINTER(0);
   polarrose_uuid_t* b = (polarrose_uuid_t*) PG_GETARG_POINTER(1);
   PG_RETURN_BOOL(polarrose_uuid_cmp_internal(a, b) == 0);
}

PG_FUNCTION_INFO_V1(polarrose_uuid_abs_ge);

Datum polarrose_uuid_abs_ge(PG_FUNCTION_ARGS)
{
   polarrose_uuid_t* a = (polarrose_uuid_t*) PG_GETARG_POINTER(0);
   polarrose_uuid_t* b = (polarrose_uuid_t*) PG_GETARG_POINTER(1);
   PG_RETURN_BOOL(polarrose_uuid_cmp_internal(a, b) >= 0);
}

PG_FUNCTION_INFO_V1(polarrose_uuid_abs_gt);

Datum polarrose_uuid_abs_gt(PG_FUNCTION_ARGS)
{
   polarrose_uuid_t* a = (polarrose_uuid_t*) PG_GETARG_POINTER(0);
   polarrose_uuid_t* b = (polarrose_uuid_t*) PG_GETARG_POINTER(1);
   PG_RETURN_BOOL(polarrose_uuid_cmp_internal(a, b) > 0);
}

PG_FUNCTION_INFO_V1(polarrose_uuid_abs_cmp);

Datum polarrose_uuid_abs_cmp(PG_FUNCTION_ARGS)
{
   polarrose_uuid_t* a = (polarrose_uuid_t*) PG_GETARG_POINTER(0);
   polarrose_uuid_t* b = (polarrose_uuid_t*) PG_GETARG_POINTER(1);
   PG_RETURN_BOOL(polarrose_uuid_cmp_internal(a, b) != 0);
}

PG_FUNCTION_INFO_V1(polarrose_uuid_to_text);

Datum polarrose_uuid_to_text(PG_FUNCTION_ARGS)
{
   polarrose_uuid_t* uuid = (polarrose_uuid_t*) PG_GETARG_POINTER(0);
   
   text* ascii = (text*) palloc(36 + VARHDRSZ);
   VARATT_SIZEP(ascii) = 36 + VARHDRSZ;
   uuid_unparse_lower(uuid->uuid, VARDATA(ascii));
   
   PG_RETURN_TEXT_P(ascii);
}

PG_FUNCTION_INFO_V1(polarrose_uuid_from_text);

Datum polarrose_uuid_from_text(PG_FUNCTION_ARGS)
{
   PG_RETURN_NULL();
}
